#include "Cluster.h"
#include <cmath>

// parse ndoes from string s
// s format:id:v;..;
// nodes insert within increasing order
Cluster::Cluster(int id, string s):m_id(id) {
    // split s
    vector<string> vec_s = util::split(s, ';');
    for(vector<string>::iterator it = vec_s.begin();
        it != vec_s.end();
        ++it){
        Node node(*it);
        insert(node);
    }
}

void Cluster::insert(const Node& node) {
    list<Node>::iterator p = m_nodes.begin();
    while (p != m_nodes.end() && p->id < node.id) ++p;
    if (p != m_nodes.end() && p->id == node.id)
        p->v = (p->v + node.v) / 2;
    else
        m_nodes.insert(p, node);
}

// decide wheather my nodes with the same id with node
bool Cluster::has_node(const Node& node) const {
    list<Node>::const_iterator p = m_nodes.begin();
    while (p != m_nodes.end() && p->id < node.id) ++p;
    return (p->id == node.id);
}

// using cosine
float Cluster::sim(const Cluster& c) {
    float sc = 0.0, s1 = 0.0, s2 = 0.0;
    const list<Node>& cnodes = c.nodes();
    list<Node>::iterator p1 = m_nodes.begin();
    list<Node>::const_iterator p2 = cnodes.begin();

    // insert with increasing order
    while( p1 != m_nodes.end() && p2 != cnodes.end() ) {
        list<Node>::const_iterator tmp = p2;            
        while (p2->id < p1->id && p2 != cnodes.end()) {
            s2 += p2->v*p2->v;
            ++p2;
        }
        if(p1->id == p2->id) {
            sc += p1->v*p2->v;
            s2 += p2->v*p2->v;
            ++p2;
        }

        s1 += p1->v*p1->v;
        ++p1;
    } // end while 1
    // cnodes is longer than m_nodes
    for(; p1 != m_nodes.end(); p1++) {
        s1 += p1->v*p1->v;
    }
    
	for(; p2 != cnodes.end(); p2++) {
		s2 += p2->v*p2->v;
	}

    return sc/sqrt(s1*s2);
}

void Cluster::combine(const Cluster& c) {
    const list<Node>& cnodes = c.nodes();
    list<Node>::iterator p1 = m_nodes.begin();
    list<Node>::const_iterator p2 = cnodes.begin();

    // insert with increasing order
    while( p1 != m_nodes.end() && p2 != cnodes.end() ) {
        list<Node>::const_iterator tmp = p2;            
        while (p2->id < p1->id && p2 != cnodes.end()) {
            ++p2;
        }

        if(tmp != p2) {
            m_nodes.insert(p1, tmp, p2);
        }
            
        if(p1->id == p2->id) {
            p1->v = (p1->v + p2->v) / 2;
            ++p2;
        }
            
        ++p1;
    } // end while 1

    // cnodes is longer than m_nodes
    if(p2 != cnodes.end()) {
        m_nodes.insert(p1, p2, cnodes.end());
    }
}// end fun
